package files;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections4.MapUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName: JsonToExcel
 * @Description: json报文转excel
 * @Author: zyy
 * @Date: 2020/08/14 11:34
 * @Version: 1.0
 */
public class JsonToExcel {
    /**
     * ebcs返回的成功的编码
     */
    public static final String RESPONSE_CODE_SUCCESS = "999999";
    /**
     * 报文深度
     */
    public static AtomicInteger depth = new AtomicInteger(0);

    /**
     * 递归方法
     *
     * @param rowList
     * @param nodeMap
     * @param columnNum 每一行都是从第0列开始的，只有有子节点的时候是父节点的columnNum+1开始
     */
    public static void recursion(List<RowAttribute> rowList, Map<String, Object> nodeMap, int columnNum) {
        //depth代表深度  columnNum代表所在列号 --》 深度取最大的列号
        if (depth.get() < columnNum) {
            depth.set(columnNum);
        }
        if (nodeMap == null || nodeMap.isEmpty()) {
            return;
        }
        //遍历一下nodeMap
        nodeMap.forEach((nodeKey, nodeValue) -> {
            if (nodeKey.equals("nodeName")) {
                //每一个nodeName节点就代表一行
                RowAttribute rowAttribute = getRowAttribute(nodeMap, columnNum, (String) nodeValue, Boolean.FALSE);
                rowList.add(rowAttribute);
            } else if (nodeKey.equals("subNodeList")) {
                //每一个subNodeList就代表有子节点，需要递归，子节点的columnNum+1
                List<Map<String, Object>> childNodeList = (List<Map<String, Object>>) nodeValue;
                if (childNodeList != null) {
                    for (Map<String, Object> childNodeMap : childNodeList) {
                        recursion(rowList, childNodeMap, columnNum + 1);
                    }
                }
            }
        });
    }


    private static RowAttribute getRowAttribute(Map<String, Object> nodeMap, int columnNum, String nodeValue, Boolean isResponseCode) {
        RowAttribute rowAttribute = new RowAttribute();
        rowAttribute.setColumnNum(columnNum);
        rowAttribute.setFieldName(nodeValue);
        rowAttribute.setRowOtherAttributes(nodeMap);
        rowAttribute.setIsResponseCode(isResponseCode);
        return rowAttribute;
    }


    public static void main(String[] args) {
        //准备数据
        Map<String, Object> applyMap = getApplyMap();
        System.out.println("投保报文：" + applyMap);
        if (MapUtils.isEmpty(applyMap)) {
            return;
        }

        //组装数据
        List<RowAttribute> rowList = getRowList(applyMap);
        //创建excel
        createExcel(rowList);
    }

    private static List<RowAttribute> getRowList(Map<String, Object> applyMap) {
        List<Map<String, Object>> paramInList = (List<Map<String, Object>>) applyMap.get("paramIn");
        List<Map<String, Object>> paramOutList = (List<Map<String, Object>>) applyMap.get("paramOut");
        List<Map<String, Object>> responseCodeList = (List<Map<String, Object>>) applyMap.get("responseCode");
        System.out.println("----入参报文：" + paramInList);
        System.out.println("----出参报文：" + paramOutList);
        System.out.println("----响应码：" + responseCodeList);

        //每行的信息
        List<RowAttribute> rowList = new ArrayList<>();

        //加入参描述
        rowList.add(getDescRowAttribute("入参"));
        //加入参头
        rowList.add(getHeadRowAttribute());
        //加入参报文
        if (paramInList != null && paramInList.size() != 0) {
            for (Map<String, Object> paramInNodeMap : paramInList) {
                recursion(rowList, paramInNodeMap, 0);
            }
        }

        //加空行
        rowList.add(getNullRowAttribute());

        //加出参描述
        rowList.add(getDescRowAttribute("出参"));
        //加出参头
        rowList.add(getHeadRowAttribute());
        //加出参报文
        if (paramOutList != null && paramOutList.size() != 0) {
            for (Map<String, Object> paramOutNodeMap : paramOutList) {
                recursion(rowList, paramOutNodeMap, 0);
            }
        }

        //加空行
        rowList.add(getNullRowAttribute());

        //加响应码描述
        rowList.add(getDescRowAttribute("响应码"));
        //加响应码头
        rowList.add(getHeadResponseCodeRow());
        //加响应码(处理方式不一样)
        if (responseCodeList != null && responseCodeList.size() != 0) {
            addResponseCodeRow(responseCodeList, rowList);
        }

        //字段(深度+1   因为字段是从0开始)
        depth.incrementAndGet();
        //是否必填(深度+1)
        depth.incrementAndGet();
        //字段类型(深度+1)
        depth.incrementAndGet();
        //字段描述(深度+1)
        depth.incrementAndGet();

        return rowList;
    }

    private static Map<String, Object> getApplyMap() {
        String jsonString = null;
        try (InputStream inputStream = new FileInputStream("D:\\document\\json.txt");
             InputStreamReader streamReader = new InputStreamReader(inputStream);
             BufferedReader bufferedReader = new BufferedReader(streamReader)) {
            StringBuffer stringBuffer = new StringBuffer();
            String line;
            while ((line = bufferedReader.readLine()) != null) {
                stringBuffer.append(line);
            }
            jsonString = stringBuffer.toString();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        //--JSON String to Map
        Map<String, Object> paramMap = JSONObject.parseObject(jsonString);
        String responseCode = Optional.ofNullable(paramMap)
                .map(map -> (String) map.get("responseCode"))
                .orElse(null);
        if (!RESPONSE_CODE_SUCCESS.equals(responseCode)) {
            return null;
        }
        return Optional.ofNullable(paramMap)
                .map(map -> (Map<String, Object>) map.get("result"))
                .map(resultMap -> (Map<String, Object>) resultMap.get("APPLY"))
                .orElse(null);

    }

    private static void createExcel(List<RowAttribute> rowList) {
        try (//创建工作簿
             Workbook workbook = new SXSSFWorkbook(1000);
             //输出流
             OutputStream outputStream = new FileOutputStream("D:\\document\\测试文档.xlsx")) {
            //创建工作表
            Sheet policySheet = workbook.createSheet("投保");
            for (int i = 0; i < rowList.size(); i++) {
                RowAttribute rowAttribute = rowList.get(i);
                Row sheetRow = policySheet.createRow(i);
                if (rowAttribute.getFieldName() == null || rowAttribute.getFieldName().length() == 0) {
                    continue;
                }
                //responseCode特殊处理
                if (rowAttribute.getIsResponseCode().booleanValue()) {
                    //code在第0列 msg在第二列
                    for (int j = 0; j <= 1; j++) {
                        Cell rowCell = sheetRow.createCell(j);
                        if (j == 0) {
                            //code在第0列
                            rowCell.setCellValue(rowAttribute.getFieldName());
                        } else {
                            //msg在第1列
                            String msg = (String) rowAttribute.getRowOtherAttributes().get("msg");
                            rowCell.setCellValue(msg);
                        }
                    }
                } else {
                    for (int j = 0; j <= depth.get(); j++) {
                        //列
                        Cell rowCell = sheetRow.createCell(j);
                        if (j == rowAttribute.getColumnNum()) {
                            //字段
                            rowCell.setCellValue(rowAttribute.getFieldName());
                        } else if (j == depth.get() - 2) {
                            //是否必填
                            String isEmpty = (String) rowAttribute.getRowOtherAttributes().get("isEmpty");
                            rowCell.setCellValue(isEmpty);

                        } else if (j == depth.get() - 1) {
                            //字段类型
                            String nodeType = (String) rowAttribute.getRowOtherAttributes().get("nodeType");
                            rowCell.setCellValue(nodeType);

                        } else if (j == depth.get()) {
                            //字段描述
                            String nodeDesc = (String) rowAttribute.getRowOtherAttributes().get("nodeDesc");
                            rowCell.setCellValue(nodeDesc);
                        } else {
                            //nothing
                            continue;
                        }

                    }
                }
            }
            //写
            workbook.write(outputStream);
            System.out.println("生成完成");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void addResponseCodeRow(List<Map<String, Object>> responseCodeList, List<RowAttribute> rowList) {
        for (Map<String, Object> responseCodeNodeMap : responseCodeList) {
            if (responseCodeNodeMap == null || responseCodeNodeMap.isEmpty()) {
                continue;
            }
            if (responseCodeNodeMap.containsKey("code")) {
                //每一个nodeName节点就代表一行
                String code = (String) responseCodeNodeMap.get("code");
                RowAttribute rowAttribute = getRowAttribute(responseCodeNodeMap, 0, code, Boolean.TRUE);
                rowList.add(rowAttribute);
            }
        }
    }

    private static RowAttribute getHeadResponseCodeRow() {
        Map<String, Object> responseCodeHeadMap = new HashMap<>();
        responseCodeHeadMap.put("msg", "responseMsg");
        return getRowAttribute(responseCodeHeadMap, 0, "responseCode", Boolean.TRUE);
    }

    private static RowAttribute getHeadRowAttribute() {
        Map<String, Object> headMap = new HashMap<>();
        headMap.put("isEmpty", "是否必填");
        headMap.put("nodeType", "字段类型");
        headMap.put("nodeDesc", "字段描述");
        return getRowAttribute(headMap, 0, "字段", Boolean.FALSE);
    }

    private static RowAttribute getNullRowAttribute() {
        return new RowAttribute();
    }

    private static RowAttribute getDescRowAttribute(String describe) {
        return getRowAttribute(new HashMap<>(), 0, describe, Boolean.FALSE);
    }
}
